home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / programming / c / icu-1.3.1 / icuapps / uconv / uconv.cpp < prev    next >
C/C++ Source or Header  |  2000-02-23  |  8KB  |  292 lines

  1. //
  2. // uconv demonstration example of ICU and codepage conversion
  3. // Purpose is to be a similar tool as the UNIX iconv program.
  4. // Shows the usage of the ICU classes: UnicodeConverterCPP, UnicodeString
  5. //
  6. // Usage: uconv [flag] [file]
  7. // -f [codeset]  Convert file from this codeset
  8. // -t [codeset]  Convert file to this code set
  9. // -l            Display all available converters
  10. // If no file is given, uconv tries to read from stdin
  11. // 
  12. // To compile: c++ -o uconv -I${ICUHOME}/include -Wall -g uconv.cpp -L${ICUHOME}/lib -licu-uc -licu-i18n
  13. //
  14. // Original contributor was Jonas Utterström <jonas.utterstrom@vittran.norrnod.se> in 1999
  15. // Permission is granted to use, copy, modify, and distribute this software
  16. //
  17.  
  18. #include <stdio.h>
  19. #include <errno.h>
  20.  
  21. // This is the UnicodeConverterCPP headerfile
  22. #include <convert.h>
  23.  
  24. // This is the UnicodeString headerfile
  25. #include <unistr.h>
  26.  
  27.  
  28.  
  29.  
  30. static const size_t buffsize = 4096;
  31.  
  32. // Print all available codepage converters
  33. void printAllConverters()
  34. {
  35.     UErrorCode err = U_ZERO_ERROR;
  36.     int32_t num;
  37.     size_t numprint = 0;
  38.     static const size_t maxline = 70;
  39.  
  40.     // getAvailable returns a string-table with all available codepages
  41.     const char* const* convtable = UnicodeConverterCPP::getAvailableNames(num, err);
  42.     if (U_FAILURE(err))
  43.     {
  44.         fprintf(stderr, "getAvailableNames failed\n");
  45.         return;
  46.     }
  47.  
  48.     for (int32_t i = 0; i<num-1; i++)
  49.     {
  50.         // ucnv_getAvailableName gets the codepage name at a specific
  51.         // index
  52.         numprint += printf("%-20s", convtable[i]);
  53.         if (numprint>maxline)
  54.         {
  55.             putchar('\n');
  56.             numprint = 0;
  57.         }
  58.     }
  59.     puts(convtable[num-1]);
  60. }
  61.  
  62. // Convert a file from one encoding to another
  63. bool convertFile(const char* fromcpage, 
  64.                  const char* tocpage, 
  65.                  FILE* infile, 
  66.                  FILE* outfile)
  67. {
  68.     bool ret = true;
  69.     UnicodeConverterCPP* convfrom = 0;
  70.     UnicodeConverterCPP* convto = 0;
  71.     UErrorCode err = U_ZERO_ERROR;
  72.     bool  flush;
  73.     const char* cbuffiter;
  74.     char* buffiter;
  75.     const size_t readsize = buffsize-1;
  76.     char* buff = 0;
  77.  
  78.     const UChar* cuniiter;
  79.     UChar* uniiter;
  80.     UChar* unibuff;
  81.  
  82.     size_t rd, totbuffsize;
  83.  
  84.  
  85.     // Create codepage converter. If the codepage or its aliases weren't
  86.     // available, it returns NULL and a failure code
  87.     convfrom = new UnicodeConverterCPP(fromcpage, err);
  88.     if (U_FAILURE(err))
  89.     {
  90.         fprintf(stderr, "Unknown codepage: %s\n", fromcpage);
  91.         goto error_exit;
  92.     }
  93.  
  94.     convto = new UnicodeConverterCPP(tocpage, err);
  95.     if (U_FAILURE(err))
  96.     {
  97.         fprintf(stderr, "Unknown codepage %s\n", tocpage);
  98.         goto error_exit;
  99.     }
  100.  
  101.     // To ensure that the buffer always is of enough size, we
  102.     // must take the worst case scenario, that is the character in the codepage
  103.     // that uses the most bytes and multiply it against the buffsize
  104.     totbuffsize = buffsize*convto->getMaxBytesPerChar();
  105.     buff = new char[totbuffsize];
  106.     unibuff = new UChar[buffsize];
  107.         
  108.     do  
  109.     {
  110.         rd = fread(buff, 1, readsize, infile);
  111.         if (ferror(infile) != 0)
  112.         {
  113.             fprintf(stderr, "Error reading from input file: %s\n", strerror(errno));
  114.             goto error_exit;
  115.         }
  116.             
  117.         // Convert the read buffer into the new coding
  118.         // After the call 'uniiter' will be placed on the last character that was converted
  119.         // in the 'unibuff'. 
  120.         // Also the 'cbuffiter' is positioned on the last converted character.
  121.         // At the last conversion in the file, flush should be set to true so that
  122.         // we get all characters converted
  123.         //
  124.         // The converter must be flushed at the end of conversion so that characters
  125.         // on hold also will be written
  126.         uniiter = unibuff;
  127.         cbuffiter = buff;
  128.         flush = rd!=readsize;        
  129.         convfrom->toUnicode(uniiter, uniiter+buffsize, cbuffiter, cbuffiter+rd, 
  130.                             NULL, flush, err);
  131.             
  132.         if (U_FAILURE(err))
  133.         {
  134.             fprintf(stderr, "Conversion to Unicode from codepage failed\n");
  135.             goto error_exit;
  136.         }
  137.             
  138.         // At the last conversion, the converted characters should be equal to number
  139.         // of chars read.
  140.         if (flush && cbuffiter!=(buff+rd))
  141.         {
  142.             fprintf(stderr, "Premature end of input, when converting from codepage to Unicode\n");
  143.             goto error_exit;
  144.         }
  145.             
  146.         // Convert the Unicode buffer into the destination codepage
  147.         // Again 'buffiter' will be placed on the last converted character
  148.         // And 'cuniiter' will be placed on the last converted unicode character
  149.         // At the last conversion flush should be set to true to ensure that 
  150.         // all characters left get converted
  151.         buffiter = buff;
  152.         cuniiter = unibuff;
  153.         convto->fromUnicode(buffiter, buffiter+totbuffsize, 
  154.                            cuniiter, cuniiter+(size_t)(uniiter-unibuff),
  155.                            NULL, flush, err);
  156.             
  157.         if (U_FAILURE(err))
  158.         {
  159.             fprintf(stderr, "Problem converting from Unicode to codepage\n");
  160.             goto error_exit;
  161.         }
  162.                         
  163.         // At the last conversion, the converted characters should be equal to number
  164.         // of consumed characters.
  165.         if (flush && cuniiter!=(unibuff+(size_t)(uniiter-unibuff)))
  166.         {
  167.             fprintf(stderr, "Premature end of Unicode conversion to codepage\n");
  168.             goto error_exit;
  169.         }
  170.             
  171.         // Finally, write the converted buffer to the output file
  172.         rd =  (size_t)(buffiter-buff);
  173.         if (fwrite(buff, 1, rd, outfile) != rd)
  174.         {
  175.             fprintf(stderr, "The converted text couldn't be written: %s \n", strerror(errno));
  176.             goto error_exit;
  177.         }
  178.         
  179.     } while (!flush); // Stop when we have flushed the converters (this means that it's the end of output)
  180.  
  181.     goto normal_exit;
  182.   error_exit:
  183.     ret = true;
  184.   normal_exit:
  185.     delete convfrom;
  186.     delete convto;
  187.  
  188.     // Close the created converters
  189.     delete [] buff;
  190.     delete [] unibuff;
  191.     return ret;
  192. }
  193.  
  194. void printUsage()
  195. {
  196.     printf("Usage: uconv [flag] [file]\n"
  197.            "-f [codeset]  Convert file from this codeset\n"
  198.            "-t [codeset]  Convert file to this code set\n"
  199.            "-h            Show this help text\n"
  200.            "-l            List all available codepages\n");
  201. }
  202.  
  203. int main(int argc, char** argv)
  204. {
  205.     FILE* file = 0;
  206.     FILE* infile;
  207.     int   ret = 0;
  208.     const char* fromcpage = 0;
  209.     const char* tocpage = 0;
  210.     const char* infilestr = 0;
  211.  
  212.     char** iter = argv+1;
  213.     char** end = argv+argc;    
  214.  
  215.     // First, get the arguments from command-line
  216.     // to know the codepages to convert between
  217.     for (; iter!=end; iter++)
  218.     {
  219.         // Check for from charset
  220.         if (strcmp("-f", *iter) == 0)
  221.         {
  222.             iter++;
  223.             if (iter!=end)
  224.                 fromcpage = *iter;
  225.         }
  226.         else if (strcmp("-t", *iter) == 0)
  227.         {
  228.             iter++;
  229.             if (iter!=end)
  230.                 tocpage = *iter;
  231.         }
  232.         else if (strcmp("-l", *iter) == 0)
  233.         {
  234.             printAllConverters();
  235.             goto normal_exit;
  236.         }
  237.         else if (strcmp("-h", *iter) == 0)
  238.         {
  239.             printUsage();
  240.             goto normal_exit;
  241.         }
  242.         else
  243.         {
  244.             infilestr = *iter;
  245.         }
  246.         
  247.     }
  248.  
  249.     if (fromcpage==0 && tocpage==0)
  250.     {
  251.         printUsage();
  252.         goto normal_exit;
  253.     }
  254.  
  255.     if (fromcpage==0)
  256.     {
  257.         fprintf(stderr, "No conversion from codeset given (use -f)\n");
  258.         goto error_exit;
  259.     }
  260.     if (tocpage==0)
  261.     {
  262.         fprintf(stderr, "No conversion to codeset given (use -t)\n");
  263.         goto error_exit;
  264.     }
  265.  
  266.     // Open the correct input file or connect to stdin for reading input
  267.     if (infilestr!=0)
  268.     {
  269.         file = fopen(infilestr, "r");
  270.         if (file==0)
  271.         {
  272.             fprintf(stderr, "Couldn't open the input file: %s\n", strerror(errno));
  273.             return 1;
  274.         }
  275.         infile = file;
  276.     }
  277.     else
  278.         infile = stdin;
  279.  
  280.     if (!convertFile(fromcpage, tocpage, infile, stdout))
  281.         goto error_exit;
  282.  
  283.     goto normal_exit;
  284.   error_exit:
  285.     ret = 1;
  286.   normal_exit:
  287.  
  288.     if (file!=0)
  289.         fclose(file);
  290.     return ret;
  291. }
  292.